package com.ecoolex.discount.sales.admin.controller;

import static com.ecoolex.discount.sales.core.CoreConstant.YOU_WORLD_GIFTCARD_CHANNEL_SECERT;

import java.math.BigDecimal;
import java.util.*;

import javax.servlet.http.HttpServletRequest;

import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import com.ecoolex.discount.sales.core.external.v2.YWExternalService;
import com.ecoolex.discount.sales.core.external.v2.pojo.*;
import com.ecoolex.discount.sales.core.service.YWService;
import com.ecoolex.discount.sales.core.utils.SignUtils;
import com.ecoolex.discount.sales.entity.YWCtripOrder;
import com.ecoolex.discount.sales.pojo.*;
import com.ecoolex.discount.sales.ws.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;

import lombok.extern.slf4j.Slf4j;

@RestController
@RequestMapping("/youworld/v2")
@Slf4j
public class YouWorldV2Controller {

	@Autowired
	YWService ywService;

	@Autowired
	YWBrandService ywBrandService;

	@Autowired
	YWStoreService ywStoreService;

	@Autowired
	YWGiftCardService ywGiftCardService;

	@Autowired
	YWGiftCardOrderService ywGiftCardOrderService;

	@Autowired
	YWExternalService ywExternalService;

	@Autowired
	YWCtripOrderService ywCtripOrderService;

	@Reference
	AdminSystemConfigService adminSystemConfigService;

	@Autowired
	ObjectMapper objectMapper;

	@Autowired
	Gson gson;

	@GetMapping("/syncBrandData")
	public void syncBrandData() {
		ywService.syncBrandData();
	}

	@GetMapping("/syncStoreData")
	public void syncStoreData() {
		ywService.syncStoreData();
	}

	@GetMapping("/syncGiftCardList")
	public void syncGiftCardList() {
		ywService.syncGiftCardListData();
	}

	@PostMapping("/getBrands")
	@ResponseBody
	public CtripYWResponse<GetBrandsDTO> getBrands(@RequestParam(name = "channelId") String channelId,
			@RequestParam(name = "serviceId") String serviceId, @RequestParam(name = "timestamp") Long timestamp,
			@RequestParam(name = "sign") String sign, HttpServletRequest request) {
		Map<String, String> params = new HashMap<>();
		Enumeration<String> paramsNames = request.getParameterNames();
		while (paramsNames.hasMoreElements()) {
			String paramName = paramsNames.nextElement();
			params.put(paramName, request.getParameter(paramName));
		}
		String secert = adminSystemConfigService
				.getByKey(String.format(YOU_WORLD_GIFTCARD_CHANNEL_SECERT, channelId).toUpperCase(Locale.ROOT));
		if (!SignUtils.verity(params, secert)) {
			CtripYWResponse ctripYWResponse = CtripYWResponse.sign();
			ctripYWResponse = SignUtils.sign(ctripYWResponse, secert, objectMapper);
			return ctripYWResponse;
		}
		List<GetBrandsDTO> brandsDTOS = ywBrandService.getAllBrands(channelId);
		CtripYWResponse ctripYWResponse = CtripYWResponse.ok().data(brandsDTOS);
		ctripYWResponse = SignUtils.sign(ctripYWResponse, secert, objectMapper);
		return ctripYWResponse;
	}

	@PostMapping("/getStores")
	@ResponseBody
	public CtripYWResponse<GetStoriesDTO> getStores(@RequestParam(name = "channelId") String channelId,
			@RequestParam(name = "serviceId") String serviceId, @RequestParam(name = "timestamp") Long timestamp,
			@RequestParam(name = "sign") String sign, HttpServletRequest request) {
		Map<String, String> params = new HashMap<>();
		Enumeration<String> paramsNames = request.getParameterNames();
		while (paramsNames.hasMoreElements()) {
			String paramName = paramsNames.nextElement();
			params.put(paramName, request.getParameter(paramName));
		}
		String secert = adminSystemConfigService
				.getByKey(String.format(YOU_WORLD_GIFTCARD_CHANNEL_SECERT, channelId).toUpperCase(Locale.ROOT));
		if (!SignUtils.verity(params, secert)) {
			CtripYWResponse ctripYWResponse = CtripYWResponse.sign();
			ctripYWResponse = SignUtils.sign(ctripYWResponse, secert, objectMapper);
			return ctripYWResponse;
		}
		List<GetStoriesDTO> brandsDTOS = ywStoreService.getAllStories(channelId);
		CtripYWResponse ctripYWResponse = CtripYWResponse.ok().data(brandsDTOS);
		ctripYWResponse = SignUtils.sign(ctripYWResponse, secert, objectMapper);
		return ctripYWResponse;
	}

	@PostMapping("/getGiftCards")
	@ResponseBody
	public CtripYWResponse<GetGiftCardDTO> getGiftCards(@RequestParam(name = "channelId") String channelId,
			@RequestParam(name = "serviceId") String serviceId, @RequestParam(name = "timestamp") Long timestamp,
			@RequestParam(name = "sign") String sign, HttpServletRequest request) {
		Map<String, String> params = new HashMap<>();
		Enumeration<String> paramsNames = request.getParameterNames();
		while (paramsNames.hasMoreElements()) {
			String paramName = paramsNames.nextElement();
			params.put(paramName, request.getParameter(paramName));
		}
		String secert = adminSystemConfigService
				.getByKey(String.format(YOU_WORLD_GIFTCARD_CHANNEL_SECERT, channelId).toUpperCase(Locale.ROOT));
		if (!SignUtils.verity(params, secert)) {
			CtripYWResponse ctripYWResponse = CtripYWResponse.sign();
			ctripYWResponse = SignUtils.sign(ctripYWResponse, secert, objectMapper);
			return ctripYWResponse;
		}
		List<GetGiftCardDTO> brandsDTOS = ywGiftCardService.getAllGiftCards(channelId);
		CtripYWResponse ctripYWResponse = CtripYWResponse.ok().data(brandsDTOS);
		ctripYWResponse = SignUtils.sign(ctripYWResponse, secert, objectMapper);
		return ctripYWResponse;
	}

	List<Integer> allowList = Collections.unmodifiableList(Arrays.asList(260, 262, 264, 369, 460, 458, 21));

	/**
	 * channelId 渠道Id <br/>
	 * serviceId 服务商Id <br/>
	 * userId 用户Id <br/>
	 * phone 用户手机号 <br/>
	 * orderNo 订单号 <br/>
	 * currency 币种：1-人民币；2-港币；3-日元；4-美元 <br/>
	 * status 订单状态：1-已支付；2-部分退款；3-全部退款 <br/>
	 * paymentTime yyyyMMddHHmmss 支付时间 <br/>
	 * paymentNo 支付流水号 <br/>
	 * refundAmount 退款金额 <br/>
	 * createTime yyyyMMddHHmmss 创建时间 <br/>
	 * cardId 礼品卡Id <br/>
	 * buyNumber 购买数量 <br/>
	 * counterPrice 礼品卡原价 <br/>
	 * realPrice 订单实付金额 <br/>
	 * cardDiscountPercent 折扣率 <br/>
	 * discountPrice 优惠金额 <br/>
	 * image 礼品卡图片 <br/>
	 * <p>
	 * 业务逻辑讨论：https://code.aliyun.com/ecovoya/discount-sales/issues/2
	 */
	@PostMapping("/generateOrder")
	@ResponseBody
	public CtripYWResponse generateOrder(@RequestParam(name = "channelId") String channelId,
			@RequestParam(name = "serviceId") String serviceId, @RequestParam(name = "timestamp") long timestamp,
			@RequestParam(name = "sign") String sign, @RequestParam(name = "userId") String userId,
			@RequestParam(name = "phone") String phone, @RequestParam(name = "orderNo") String orderNo,
			@RequestParam(name = "currency") int currency, @RequestParam(name = "status") int status,
			@RequestParam(name = "paymentTime") String paymentTime, @RequestParam(name = "paymentNo") String paymentNo,
			@RequestParam(name = "refundAmount", required = false) java.math.BigDecimal refundAmount,
			@RequestParam(name = "createTime") String createTime, @RequestParam(name = "cardId") int cardId,
			@RequestParam(name = "buyNumber") int buyNumber,
			@RequestParam(name = "counterPrice", required = false) BigDecimal counterPrice,
			@RequestParam(name = "realPrice") BigDecimal realPrice,
			@RequestParam(name = "cardDiscountPercent") BigDecimal cardDiscountPercent,
			@RequestParam(name = "discountPrice") BigDecimal discountPrice,
			@RequestParam(name = "image", required = false) String image, HttpServletRequest request) {
		Map<String, String> params = new HashMap<>();
		Enumeration<String> paramsNames = request.getParameterNames();
		while (paramsNames.hasMoreElements()) {
			String paramName = paramsNames.nextElement();
			params.put(paramName, request.getParameter(paramName));
		}
		log.info("generateOrder-request:{}", gson.toJson(params));
		String secert = adminSystemConfigService
				.getByKey(String.format(YOU_WORLD_GIFTCARD_CHANNEL_SECERT, channelId).toUpperCase(Locale.ROOT));
		if (!SignUtils.verity(params, secert)) {
			CtripYWResponse ctripYWResponse = CtripYWResponse.sign();
			ctripYWResponse = SignUtils.sign(ctripYWResponse, secert, objectMapper);
			return ctripYWResponse;
		}
		if (!allowList.contains(cardId)) {
			return SignUtils.sign(CtripYWResponse.system().errmsg(String.format("生产环境测试阶段不支持此礼品卡:%s", cardId)), secert,
					objectMapper);
		}

		GenerateCtripOrderDTO generateCtripOrderDTO = new GenerateCtripOrderDTO();
		PropertyMapper propertyMapper = PropertyMapper.get().alwaysApplyingWhenNonNull();
		propertyMapper.from(channelId).to(generateCtripOrderDTO::setChannelId);
		propertyMapper.from(serviceId).to(generateCtripOrderDTO::setServiceId);
		propertyMapper.from(userId).to(generateCtripOrderDTO::setUserId);
		propertyMapper.from(phone).to(generateCtripOrderDTO::setPhone);
		propertyMapper.from(orderNo).to(generateCtripOrderDTO::setOrderNo);
		propertyMapper.from(currency).to(generateCtripOrderDTO::setCurrency);
		propertyMapper.from(status).to(generateCtripOrderDTO::setStatus);
		propertyMapper.from(paymentTime).to(generateCtripOrderDTO::setPaymentTime);
		propertyMapper.from(paymentNo).to(generateCtripOrderDTO::setPaymentNo);
		propertyMapper.from(refundAmount).to(generateCtripOrderDTO::setRefundAmount);
		propertyMapper.from(createTime).to(generateCtripOrderDTO::setCreateTime);
		propertyMapper.from(cardId).to(generateCtripOrderDTO::setCardId);
		propertyMapper.from(buyNumber).to(generateCtripOrderDTO::setBuyNumber);
		propertyMapper.from(counterPrice).to(generateCtripOrderDTO::setCounterPrice);
		propertyMapper.from(realPrice).to(generateCtripOrderDTO::setRealPrice);
		propertyMapper.from(cardDiscountPercent).to(generateCtripOrderDTO::setCardDiscountPercent);
		propertyMapper.from(discountPrice).to(generateCtripOrderDTO::setDiscountPrice);
		propertyMapper.from(image).to(generateCtripOrderDTO::setImage);

		YWCtripOrder order = ywCtripOrderService.save(generateCtripOrderDTO);
		if (Objects.nonNull(order)) {
			YWCardInfoDTO dto = ywGiftCardOrderService.generateGiftCard(generateCtripOrderDTO);
			return CtripYWResponse.errno(dto.getResultCode()).errmsg(dto.getMessage());
		}
		else {
			return CtripYWResponse.system().errmsg("订单已经不能重复推送");
		}
	}

	@PostMapping("/sendRefundRequest")
	@ResponseBody
	public CtripYWCommonResponse sendRefundRequest(@RequestParam(name = "channelId") String channelId,
			@RequestParam(name = "serviceId") String serviceId, @RequestParam(value = "timestamp") long timestamp,
			@RequestParam(value = "sign") String sign, @RequestParam(value = "orderNo") String orderNo,
			@RequestParam(value = "cardUsed") Boolean cardUsed, @RequestParam(value = "reasonType") String reasonType,
			@RequestParam(value = "reasonComments", required = false) String reasonComments,
			HttpServletRequest request) {
		CtripYWCommonResponse response = new CtripYWCommonResponse();
		Map<String, String> params = new HashMap<>();
		Enumeration<String> paramsNames = request.getParameterNames();
		while (paramsNames.hasMoreElements()) {
			String paramName = paramsNames.nextElement();
			params.put(paramName, request.getParameter(paramName));
		}
		log.info("sendRefundRequest-request:{}", gson.toJson(params));
		String secert = adminSystemConfigService
				.getByKey(String.format(YOU_WORLD_GIFTCARD_CHANNEL_SECERT, channelId).toUpperCase(Locale.ROOT));
		if (!SignUtils.verity(params, secert)) {
			CtripYWResponse ctripYWResponse = CtripYWResponse.sign();
			ctripYWResponse = SignUtils.sign(ctripYWResponse, secert, objectMapper);
			response.setErrno(ctripYWResponse.getErrno());
			response.setErrmsg(ctripYWResponse.getErrmsg());
			return response;
		}

		PropertyMapper mapper = PropertyMapper.get().alwaysApplyingWhenNonNull();
		SendRefundRequest refundRequest = new SendRefundRequest();
		mapper.from(channelId).to(refundRequest::setChannelId);
		mapper.from(serviceId).to(refundRequest::setServiceId);
		mapper.from(orderNo).to(refundRequest::setOrderNo);
		mapper.from(cardUsed).to(refundRequest::setCardUsed);
		mapper.from(reasonType).to(refundRequest::setReasonType);
		mapper.from(reasonComments).to(refundRequest::setReasonComments);

		try {
			String token = ywExternalService.getToken(channelId);
			SendRefundResponse sendRefundResponse = ywExternalService.sendRefundRequest(refundRequest, token);
			if (CtripYWResponse.SUCCESS.equals(sendRefundResponse.getErrno())
					&& Objects.nonNull(sendRefundResponse.getData())
					&& StringUtils.hasText(sendRefundResponse.getData().getMessage())) {
				response.setErrno(sendRefundResponse.getErrno());
				response.setErrmsg(sendRefundResponse.getData().getMessage());
			}
			else {
				response.setErrno(sendRefundResponse.getErrno());
				response.setErrmsg(sendRefundResponse.getErrmsg());
			}
		}
		catch (Exception e) {
			log.error(e.getMessage(), e);
			CtripYWResponse ctripYWResponse = CtripYWResponse.system().errmsg(e.getMessage());
			response.setErrno(ctripYWResponse.getErrno());
			response.setErrmsg(ctripYWResponse.getErrmsg());
		}
		return response;
	}

	@PostMapping("/cancelRefundRepuest")
	@ResponseBody
	public CtripYWCommonResponse cancelRefundRepuest(@RequestParam(name = "channelId") String channelId,
			@RequestParam(name = "serviceId") String serviceId, @RequestParam(value = "timestamp") long timestamp,
			@RequestParam(value = "sign") String sign, @RequestParam(value = "orderNo") String orderNo,
			HttpServletRequest request) {

		Map<String, String> params = new HashMap<>();
		CtripYWCommonResponse response = new CtripYWCommonResponse();
		Enumeration<String> paramsNames = request.getParameterNames();
		while (paramsNames.hasMoreElements()) {
			String paramName = paramsNames.nextElement();
			params.put(paramName, request.getParameter(paramName));
		}
		log.info("cancelRefundRepuest-request:{}", gson.toJson(params));
		String secert = adminSystemConfigService
				.getByKey(String.format(YOU_WORLD_GIFTCARD_CHANNEL_SECERT, channelId).toUpperCase(Locale.ROOT));
		if (!SignUtils.verity(params, secert)) {
			CtripYWResponse ctripYWResponse = CtripYWResponse.sign();
			ctripYWResponse = SignUtils.sign(ctripYWResponse, secert, objectMapper);
			response.setErrno(ctripYWResponse.getErrno());
			response.setErrmsg(ctripYWResponse.getErrmsg());
			return response;
		}

		PropertyMapper mapper = PropertyMapper.get().alwaysApplyingWhenNonNull();
		CancelRefundRequest refundRequest = new CancelRefundRequest();
		mapper.from(channelId).to(refundRequest::setChannelId);
		mapper.from(serviceId).to(refundRequest::setServiceId);
		mapper.from(orderNo).to(refundRequest::setOrderNo);

		try {
			String token = ywExternalService.getToken(channelId);
			CancelRefundResponse cancelRefundResponse = ywExternalService.cancelRefundRepuest(refundRequest, token);
			if (CtripYWResponse.SUCCESS.equals(cancelRefundResponse.getErrno())
					&& Objects.nonNull(cancelRefundResponse.getData())
					&& StringUtils.hasText(cancelRefundResponse.getData().getMessage())) {
				response.setErrno(cancelRefundResponse.getErrno());
				response.setErrmsg(cancelRefundResponse.getData().getMessage());
			}
			else {
				response.setErrno(cancelRefundResponse.getErrno());
				response.setErrmsg(cancelRefundResponse.getErrmsg());
			}
		}
		catch (Exception e) {
			log.error(e.getMessage(), e);
			CtripYWResponse ctripYWResponse = CtripYWResponse.system().errmsg(e.getMessage());
			response.setErrno(ctripYWResponse.getErrno());
			response.setErrmsg(ctripYWResponse.getErrmsg());
		}
		return response;
	}

	@PostMapping("/checkRefundStatus")
	@ResponseBody
	public CheckRefundStatusFlatResponse checkRefundStatus(@RequestParam(value = "timestamp") long timestamp,
			@RequestParam(value = "sign") String sign, @RequestParam(value = "orderNo") String orderNo,
			@RequestParam(name = "channelId") String channelId, @RequestParam(name = "serviceId") String serviceId,
			HttpServletRequest request) {

		Map<String, String> params = new HashMap<>();
		Enumeration<String> paramsNames = request.getParameterNames();
		while (paramsNames.hasMoreElements()) {
			String paramName = paramsNames.nextElement();
			params.put(paramName, request.getParameter(paramName));
		}
		log.info("checkRefundStatus-request:{}", gson.toJson(params));
		CheckRefundStatusFlatResponse response = new CheckRefundStatusFlatResponse();
		String secert = adminSystemConfigService
				.getByKey(String.format(YOU_WORLD_GIFTCARD_CHANNEL_SECERT, channelId).toUpperCase(Locale.ROOT));
		if (!SignUtils.verity(params, secert)) {
			CtripYWResponse ctripYWResponse = CtripYWResponse.sign();
			ctripYWResponse = SignUtils.sign(ctripYWResponse, secert, objectMapper);
			response.setErrno(ctripYWResponse.getErrno());
			response.setErrmsg(ctripYWResponse.getErrmsg());
			return response;
		}

		PropertyMapper mapper = PropertyMapper.get().alwaysApplyingWhenNonNull();
		CheckRefundStatusRequest refundRequest = new CheckRefundStatusRequest();
		mapper.from(orderNo).to(refundRequest::setOrderNo);
		mapper.from(channelId).to(refundRequest::setChannelId);
		mapper.from(serviceId).to(refundRequest::setServiceId);
		try {
			String token = ywExternalService.getToken(channelId);
			CheckRefundStatusResponse checkRefundStatus = ywExternalService.checkRefundStatus(refundRequest, token);
			if (Objects.nonNull(checkRefundStatus)) {
				response.setErrno(checkRefundStatus.getErrno());
				response.setErrmsg(checkRefundStatus.getErrmsg());
				if (Objects.nonNull(checkRefundStatus.getData())) {
					response.setRefundStatus(checkRefundStatus.getData().getRefundStatus());
					response.setCustomerServiceReply(checkRefundStatus.getData().getCustomerServiceReply());
				}
			}
			return response;
		}
		catch (Exception e) {
			log.error(e.getMessage(), e);
			response.setErrmsg(e.getMessage());
			response.setErrno(CtripYWResponse.SYSTEM);
			return response;
		}
	}

	@PostMapping("/checkCardStatus")
	@ResponseBody
	public QueryGiftCardStockStatusResponse checkCardStatus(@RequestParam(value = "timestamp") long timestamp,
			@RequestParam(value = "sign") String sign, @RequestParam(value = "cardId") Long cardId,
			@RequestParam(value = "cardName") String cardName, @RequestParam(name = "channelId") String channelId,
			@RequestParam(name = "serviceId") String serviceId, HttpServletRequest request) {

		Map<String, String> params = new HashMap<>();
		Enumeration<String> paramsNames = request.getParameterNames();
		while (paramsNames.hasMoreElements()) {
			String paramName = paramsNames.nextElement();
			params.put(paramName, request.getParameter(paramName));
		}
		log.info("checkRefundStatus-request:{}", gson.toJson(params));
		QueryGiftCardStockStatusResponse response = new QueryGiftCardStockStatusResponse();
		CheckCardStatusRequest requestEntity = new CheckCardStatusRequest();
		PropertyMapper mapper = PropertyMapper.get().alwaysApplyingWhenNonNull();
		mapper.from(channelId).to(requestEntity::setChannelId);
		mapper.from(serviceId).to(requestEntity::setServiceId);
		mapper.from(cardId).to(requestEntity::setCardId);
		mapper.from(cardName).to(requestEntity::setName);
		String token = ywExternalService.getToken(channelId);
		CheckCardStatusResponse checkCardStatusResponse = ywExternalService.checkCardStatus(requestEntity, token);
		mapper.from(checkCardStatusResponse::getErrno).to(response::setErrno);
		mapper.from(checkCardStatusResponse::getErrmsg).to(response::setErrmsg);
		CheckCardStatusResponse.Item item = checkCardStatusResponse.getData();
		mapper.from(item::getStatus).to(response::setCardStatus);
		return response;
	}

}
